import { message } from 'ant-design-vue'
import request from '@/utils/request'

// 允许的文件类型
const ALLOWED_FILE_TYPES = ['image/jpeg', 'image/png', 'image/gif', 'image/webp', 'image/jpg']
// 最大文件大小（10MB）
const MAX_FILE_SIZE = 10 * 1024 * 1024
// 图片压缩质量
const IMAGE_QUALITY = 0.8
// 最大图片尺寸
const MAX_IMAGE_WIDTH = 1920
const MAX_IMAGE_HEIGHT = 1080

// API路径
const API = {
  FILE_UPLOAD: '/oss/api-admin/file/upload'
}

/**
 * 上传选项接口
 */
export interface UploadOptions {
  onProgress?: (percent: number) => void  // 上传进度回调
  onSuccess?: (url: string) => void       // 上传成功回调
  onError?: (error: Error) => void        // 上传失败回调
  autoCompress?: boolean                  // 是否自动压缩图片
  maxWidth?: number                       // 最大宽度
  maxHeight?: number                      // 最大高度
  quality?: number                        // 压缩质量(0-1)
}

/**
 * 验证文件类型和大小
 * @param file 要验证的文件
 * @returns 是否通过验证
 */
export const validateFile = (file: File): boolean => {
  // 检查文件类型
  if (!ALLOWED_FILE_TYPES.includes(file.type)) {
    message.error('只支持JPG/PNG/GIF/WEBP格式的图片')
    return false
  }
  
  // 检查文件大小
  if (file.size > MAX_FILE_SIZE) {
    message.error(`文件大小不能超过${MAX_FILE_SIZE / 1024 / 1024}MB`)
    return false
  }
  
  return true
}

/**
 * 压缩图片
 * @param file 原始图片文件
 * @param options 压缩选项
 * @returns 压缩后的文件
 */
export const compressImage = (
  file: File, 
  options: {
    maxWidth?: number
    maxHeight?: number
    quality?: number
  } = {}
): Promise<File> => {
  return new Promise((resolve, reject) => {
    const { 
      maxWidth = MAX_IMAGE_WIDTH, 
      maxHeight = MAX_IMAGE_HEIGHT, 
      quality = IMAGE_QUALITY 
    } = options

    // 如果是GIF图片，不进行压缩
    if (file.type === 'image/gif') {
      resolve(file)
      return
    }

    const canvas = document.createElement('canvas')
    const ctx = canvas.getContext('2d')!
    const img = new Image()

    img.onload = () => {
      // 计算压缩后的尺寸
      let { width, height } = img
      
      if (width > maxWidth || height > maxHeight) {
        const ratio = Math.min(maxWidth / width, maxHeight / height)
        width *= ratio
        height *= ratio
      }

      canvas.width = width
      canvas.height = height

      // 绘制压缩后的图片
      ctx.drawImage(img, 0, 0, width, height)

      // 转换为Blob
      canvas.toBlob(
        (blob) => {
          if (blob) {
            const compressedFile = new File([blob], file.name, {
              type: file.type,
              lastModified: Date.now()
            })
            resolve(compressedFile)
          } else {
            reject(new Error('图片压缩失败'))
          }
        },
        file.type,
        quality
      )
    }

    img.onerror = () => reject(new Error('图片加载失败'))
    img.src = URL.createObjectURL(file)
  })
}

/**
 * 生成图片预览URL
 * @param file 图片文件
 * @returns 预览URL
 */
export const getImagePreviewUrl = (file: File): string => {
  return URL.createObjectURL(file)
}

/**
 * 上传文件到指定API
 * @param file 要上传的文件
 * @param options 上传选项
 * @returns 成功返回文件URL，失败返回null
 */
export const uploadFile = async (file: File, options: UploadOptions = {}): Promise<string | null> => {
  const {
    onProgress,
    onSuccess,
    onError,
    autoCompress = true,
    maxWidth,
    maxHeight,
    quality
  } = options

  try {
    // 验证文件
    if (!validateFile(file)) {
      return null
    }

    // 处理进度
    onProgress?.(0)

    // 自动压缩图片
    let fileToUpload = file
    if (autoCompress && file.type.startsWith('image/')) {
      try {
        fileToUpload = await compressImage(file, { maxWidth, maxHeight, quality })
        console.log(`图片压缩完成，原始大小：${(file.size / 1024).toFixed(2)}KB，压缩后大小：${(fileToUpload.size / 1024).toFixed(2)}KB`)
      } catch (error) {
        console.warn('图片压缩失败，使用原始文件:', error)
        fileToUpload = file
      }
    }

    // 准备表单数据
    const formData = new FormData()
    formData.append('file', fileToUpload)
    
    onProgress?.(20)

    // 使用原生axios请求以支持上传进度
    const response = await request.post(API.FILE_UPLOAD, formData, {
      headers: {
        'Content-Type': 'multipart/form-data'
      },
      onUploadProgress: (progressEvent: { loaded: number; total?: number }) => {
        if (progressEvent.total) {
          const percent = Math.round((progressEvent.loaded * 80) / progressEvent.total) + 20
          onProgress?.(Math.min(percent, 100))
        }
      }
    })
    
    onProgress?.(100)

    // 处理响应
    let fileUrl: string
    
    if (response.data?.success) {
      fileUrl = response.data.data
    } else if (typeof response.data === 'string') {
      // 兼容直接返回字符串URL的情况
      fileUrl = response.data
    } else {
      const errorMsg = response.data?.message || '上传失败'
      message.error(errorMsg)
      onError?.(new Error(errorMsg))
      return null
    }

    onSuccess?.(fileUrl)
    return fileUrl

  } catch (error) {
    console.error('文件上传异常:', error)
    const errorMsg = '文件上传服务异常，请稍后重试'
    message.error(errorMsg)
    onError?.(error as Error)
    return null
  }
}

/**
 * 为Ant Design的Upload组件提供自定义上传函数
 * @param uploadOptions Upload组件的请求选项
 * @param customOptions 自定义上传选项
 * @returns 上传结果Promise
 */
export const customUpload = async (
  uploadOptions: any, 
  customOptions: Omit<UploadOptions, 'onSuccess' | 'onError'> = {}
) => {
  const { file, onSuccess, onError, onProgress } = uploadOptions
  
  try {
    const url = await uploadFile(file, {
      ...customOptions,
      onProgress: (percent) => {
        onProgress?.({ percent })
      },
      onSuccess: (url) => {
        onSuccess?.(url, file)
      },
      onError: (error) => {
        onError?.(error)
      }
    })
    
    if (!url) {
      onError?.(new Error('上传失败'))
    }
  } catch (error) {
    onError?.(error)
  }
}

/**
 * 文件上传工具类
 */
export class FileUploader {
  private options: UploadOptions

  constructor(options: UploadOptions = {}) {
    this.options = options
  }

  /**
   * 上传单个文件
   */
  async upload(file: File): Promise<string | null> {
    return uploadFile(file, this.options)
  }

 
  /**
   * 更新上传选项
   */
  setOptions(options: Partial<UploadOptions>) {
    this.options = { ...this.options, ...options }
  }
}

// 导出默认实例
export const defaultUploader = new FileUploader({
  autoCompress: true,
  quality: IMAGE_QUALITY,
  maxWidth: MAX_IMAGE_WIDTH,
  maxHeight: MAX_IMAGE_HEIGHT
}) 